package deng.spring.userwebapp.services.plainhibernate;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Example;

import deng.spring.userwebapp.dal.entities.User;
import deng.spring.userwebapp.services.PasswordNotMatchedException;
import deng.spring.userwebapp.services.UserService;
import deng.spring.userwebapp.services.UsernameNotFoundException;

public class HibernateUserService extends AbstractHibernateCrudDao<User, Long> implements UserService {
	
	@Override
	public User authenticate(final String username, final String password)
			throws UsernameNotFoundException, PasswordNotMatchedException {
		
		final User exampleEntity = new User();
		exampleEntity.setUsername(username);
		
		Criteria executableCriteria = getSession().createCriteria(getEntityClass());
		executableCriteria.add(Example.create(exampleEntity));
		List<?> userList = executableCriteria.list();
		
		if (userList.size() == 0) {
			throw new UsernameNotFoundException("Username: " + username);
		}
		
		User user = (User)userList.get(0);
		String userPassword = user.getPassword();
		if (userPassword != null && !userPassword.equals(password)) {
			throw new PasswordNotMatchedException("Password not matched for username: " + username);
		}
		
		return user;
	}
	
	@Override
	public int getUserCount() {
		// Returned Object type should be Long
		Object result = getSession().createQuery("select count(e) from User e").uniqueResult();
		return ((Number)result).intValue();
	}

	@Override
	public List<User> getUsers(int firstResult, int maxResult) {
		List<?> result = getSession().createQuery("from User e order by e.username")
			.setFirstResult(firstResult)
			.setMaxResults(maxResult)
			.list();
		@SuppressWarnings("unchecked")
		List<User> users = (List<User>)result;
		return users;
	}

	@Override
	public boolean usernameExists(String username) {
		Object result = getSession().createQuery("select count(*) from User e where e.username = :username")
			.setParameter("username", username).uniqueResult();
		return ((Number)result).intValue() == 1;
	}
		
}
